
#include "util.h"

#include <sys/syscall.h>    /* for SYS_gettid */
#include <unistd.h>         /* for syscall() */

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>

__thread int t_cachedTid = 0;

int current_tid(void)
{
    if (t_cachedTid == 0)
    {
        t_cachedTid = (int)syscall(SYS_gettid);
    }

    return t_cachedTid;
}

static log_level_e g_log_level = LOG_LEVEL_INFO;
static FILE *g_out_fp = NULL;

void log_setlevel(log_level_e level)
{
    g_log_level = level;
}

static
void log_write(log_level_e level, const char *file, int line, const char *fmt, va_list ap)
{
    char content[1024];
    char time_head[28]; /* 2014-08-17 12:37:00.555 */
    const char *level_text = "NONE";
    
    FILE *fp;

    struct timeval tv;
    time_t tt;
    struct tm tm;

    if (g_log_level < level)
    {
        return;
    }

    if (LOG_LEVEL_LOG == level)
    {
        level_text = "LOG";
    }
    else if (LOG_LEVEL_ERROR == level)
    {
        level_text = "ERROR";
    }
    else if (LOG_LEVEL_WARN == level)
    {
        level_text = "WARN";
    }
    else if (LOG_LEVEL_INFO == level)
    {
        level_text = "INFO";
    }
    else if (LOG_LEVEL_DEBUG == level)
    {
        level_text = "DEBUG";
    }

    memset(time_head, 0, sizeof(time_head));
    gettimeofday(&tv, NULL);
    tt = tv.tv_sec;
    localtime_r(&tt, &tm);
    snprintf(time_head, sizeof(time_head)-1, "%u-%02u-%02u %02u:%02u:%02u.%03u", 
        tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (unsigned)(tv.tv_usec/1000));

    memset(content, 0, sizeof(content));
    vsnprintf(content, sizeof(content)-1, fmt, ap);

    fp = g_out_fp;
    if (NULL == fp)
    {
        fp = stderr;
    }

    fprintf(fp, "[%s][%s] thread: %d on %s:%d %s\n", time_head, level_text, current_tid(), file, line, content);

    return;
}

void log_print(log_level_e level, const char *file, int line, const char *fmt, ...)
{
    const char *base_file = file;
    char *sep_pos = strrchr(file, '/');
    if (sep_pos != NULL) { base_file = sep_pos + 1; }

    va_list ap;

    va_start(ap, fmt);
    log_write(level, base_file, line, fmt, ap);
    va_end(ap);

    return;
}
